{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "458b4cd9",
   "metadata": {},
   "source": [
    "# Optimization of the Object Detection Operator with YOLO"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a34f387",
   "metadata": {},
   "source": [
    "[Ultralytics YOLOv8](https://github.com/ultralytics/ultralytics) is a cutting-edge, state-of-the-art (SOTA) model that builds upon the success of previous YOLO versions and introduces new features and improvements to further boost performance and flexibility. YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of object detection and tracking, instance segmentation, image classification and pose estimation tasks."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53dc444c",
   "metadata": {},
   "source": [
    "## Run with YOLO\n",
    "\n",
    "First, let's run YOLO prediction code, which will be very simple according to the [tutorial](https://docs.ultralytics.com/modes/predict/)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4b5b2ce6",
   "metadata": {},
   "outputs": [],
   "source": [
    "from ultralytics import YOLO\n",
    "model = YOLO(\"yolov8n.pt\") \n",
    "result = model(\"https://ultralytics.com/images/bus.jpg\")[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e01490e3",
   "metadata": {},
   "source": [
    "Then, we can get the information we want based on the predicted `result`, such as `boxes`, `classes` and `scores`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5e163003",
   "metadata": {},
   "outputs": [],
   "source": [
    "boxes = [list(map(int, xyxy)) for xyxy in result.boxes.xyxy]\n",
    "classes = [result.names[int(i)] for i in result.boxes.cls]\n",
    "scores = result.boxes.conf.tolist()\n",
    "print(boxes, classes, scores)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c6874eb",
   "metadata": {},
   "source": [
    "## Develop yolo operator\n",
    "\n",
    "According to [yolov5 operator](https://towhee.io/object-detection/yolov5), we can run the pipeline for image object  detection in the following code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5ac79368",
   "metadata": {},
   "outputs": [],
   "source": [
    "from towhee import pipe, ops, DataCollection\n",
    "\n",
    "p = (\n",
    "    pipe.input('path')\n",
    "        .map('path', 'img', ops.image_decode.cv2_rgb())\n",
    "        .map('img', ('box', 'class', 'score'), ops.object_detection.yolov5())\n",
    "        .map(('img', 'box'), 'object', ops.image_crop(clamp=True))\n",
    "        .output('img', 'object', 'class')\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c86c59d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "DataCollection(p(\"https://ultralytics.com/images/bus.jpg\")).show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "678b3d3a",
   "metadata": {},
   "source": [
    "Next, we can optimize the yolo arithmetic so as to support the yolov8 model, so we can develop yolov8 operator based on the yolov5 operator, for example, we develop the YOLOv8 class and develop the `__init__` and `__call__` function, so as to support YOLOv8 model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e4e06fc8",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy\n",
    "from towhee import register\n",
    "from towhee.operator import NNOperator\n",
    "from ultralytics import YOLO\n",
    "\n",
    "\n",
    "@register(name='yolov8')\n",
    "class YOLOv8(NNOperator):\n",
    "    def __init__(self, model=\"yolov8n.pt\"):\n",
    "        super().__init__()\n",
    "        self._model = YOLO(model)\n",
    "\n",
    "    def __call__(self, img: numpy.ndarray):\n",
    "        results = self._model(img)[0]\n",
    "        boxes = [list(map(int, xyxy)) for xyxy in result.boxes.xyxy]\n",
    "        classes = [result.names[int(i)] for i in result.boxes.cls]\n",
    "        scores = result.boxes.conf.tolist()\n",
    "        return boxes, classes, scores\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9301040",
   "metadata": {},
   "source": [
    "If you compare the YOLOv8 class with the YOLOv5 class, you will see that they are very similar, the difference is the usage of the models.\n",
    "\n",
    "Then, we can also take the names `yolov8` operator to the pipeline, a similar pipeline as above, but changing the operator to YOLOv8."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a336ab8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from towhee import pipe, ops, DataCollection\n",
    "\n",
    "p = (\n",
    "    pipe.input('path')\n",
    "        .map('path', 'img', ops.image_decode.cv2_rgb())\n",
    "        .map('img', ('box', 'class', 'score'), ops.yolov8(model=\"yolov8n.pt\"))\n",
    "        .map(('img', 'box'), 'object', ops.image_crop(clamp=True))\n",
    "        .output('img', 'object', 'class')\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "442ebf2d",
   "metadata": {},
   "outputs": [],
   "source": [
    "DataCollection(p(\"https://ultralytics.com/images/bus.jpg\")).show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54ac8f7a",
   "metadata": {},
   "source": [
    "Now we have completed the development of the YOLOv8 operator, as well as adding the operator to the pipeline, and the YOLOv8 model detects one more object, the stop sign, compared to the YOLOv5 model, so it is clear that YOLOv8 is a more complete detection than YOLOv5.\n",
    "\n",
    "We can also develop the `__init__` and `__call__` methods according to how models such as YOLOv6 are used, for example, to enable different models."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2943fa74",
   "metadata": {},
   "source": [
    "## Set for training\n",
    "\n",
    "We can also train the YOLOv8 operator, according to the method of [YOLOv8 training](https://github.com/ultralytics/ultralytics/blob/dce4efce48a05e028e6ec430045431c242e52484/docs/yolov5/tutorials/train_custom_data.md), first of all, you have to manually create a \"dataset\" directory in the current directory, and then you can use COCO dataset to train the YOLOv8 model, or you can replace it with your own dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9694e1e1",
   "metadata": {},
   "outputs": [],
   "source": [
    "import towhee\n",
    "\n",
    "op = towhee.ops.yolov8().get_op()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "340c963c",
   "metadata": {},
   "outputs": [],
   "source": [
    "op._model.train(data=\"coco128.yaml\", epochs=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f9004cb5",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
